package wangwenjun.phase3.executor.completablefuture.demo02;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author ChangLiang
 * @date 2020/6/26
 */
@Slf4j
public class AppV4Test {

    private static Integer corePoolSize = 4;

    private static CountDownLatch countDownLatch;

    @Test
    @DisplayName("test")
    public void test(){

        /**
         * 并行执行 并且满足统一超时时间
         *
         */

        List<String> list = new ArrayList<>();

        countDownLatch = new CountDownLatch(4);

        log.warn("start");
        long start = System.currentTimeMillis();

        EsService esService = new EsService();

        // 使用全局线程池
        ThreadPoolExecutor threadPoolExecutor = SearchRequestThreadPool.getExecutor();
        threadPoolExecutor.execute(new QueryThread(countDownLatch, esService, "searchQueryItems",
                new Class<?>[]{String.class}, new
                Object[]{"changliang"}, list));
        threadPoolExecutor.execute(new QueryThread(countDownLatch, esService, "searchQueryGuides",
                new Class<?>[]{String.class}, new
                Object[]{"changliang"}, list));
        threadPoolExecutor.execute(new QueryThread(countDownLatch, esService, "getApplications",
                new Class<?>[]{String.class}, new
                Object[]{"changliang"}, list));
        threadPoolExecutor.execute(new QueryThread(countDownLatch, esService, "getAppointItems",
                new Class<?>[]{String.class}, new
                Object[]{"changliang"}, list));

        // 等待线程执行完毕
        try {

            /**
             * 统一时间控制
             */

            countDownLatch.await(3,TimeUnit.SECONDS);
            long end = System.currentTimeMillis();
            log.warn("full execution time consumption:{} ms", (end - start));
            log.info("result:{}", list);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            threadPoolExecutor.shutdown();
            try {
                threadPoolExecutor.awaitTermination(1, TimeUnit.MINUTES);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    class QueryThread implements Runnable {

        protected CountDownLatch countDownLatch;

        protected Object target;

        protected String methodName;

        protected Class<?>[] parameterTypes;

        protected Object[] params;

        protected List<String> list;

        public QueryThread(CountDownLatch countDownLatch, Object target, String methodName, Class<?>[]
                parameterTypes, Object[] params, List<String> list) {
            this.countDownLatch = countDownLatch;
            this.target = target;
            this.methodName = methodName;
            this.parameterTypes = parameterTypes;
            this.params = params;
            this.list = list;
        }

        @Override
        public void run() {
            try {
                query();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (countDownLatch != null) {
                    countDownLatch.countDown();
                }
            }
        }

        public void query() {
            try {
                Method method = this.target.getClass().getDeclaredMethod(methodName, parameterTypes);
                Object returnValue = method.invoke(target, params);
                String value = returnValue != null ? returnValue.toString() : null;
                list.add(value);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }
}
